/*******************************************************************************
 * Copyright (c) 2008 Sylvain Sicard.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the GNU Lesser Public License v2.1
 * which accompanies this distribution, and is available at
 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
 * 
 * Contributors:
 *     Noel De Palma - initial API and implementation
 ******************************************************************************/
package fr.jade.service.nodes.manager;

import java.util.HashMap;
import java.util.Map;

import org.objectweb.fractal.api.Component;
import org.objectweb.fractal.api.NoSuchInterfaceException;
import org.objectweb.fractal.api.control.BindingController;
import org.objectweb.fractal.api.control.IllegalBindingException;
import org.objectweb.fractal.api.control.IllegalLifeCycleException;
import org.objectweb.fractal.api.factory.InstantiationException;

import fr.jade.base.JadeBaseComponent;
import fr.jade.console.cmd.Boot;
import fr.jade.fraclite.orb.registry.NamingService;
import fr.jade.service.ManagerService;
import fr.jade.service.nodes.ClusterManager;
import fr.jade.service.nodes.allocator.Allocator;
import fr.jade.service.nodes.factory.NodeFactory;
import fr.jade.util.JadeException;


/**
 * This class launch an nodes adl file.
 * The adlfile to launch is configured either in the attribute adlFile 
 * or either in a property file. The name of the property file is defined 
 * by the attribute adlFileProperty. In this latter case, the name of the key is :
 * "deploymentService.applicationLauncher.adlFile". The name of this key is not 
 * configurable for now. The adlFileProperty is an argument of 
 * NodesLauncher.fractal. 
 
 * @author nono
 * @contact noel.depalma@inrialpes.fr
 */

/**
 * @author Noel De Palma
 * @author Sylvain Sicard
 * @contact Sylvain.sicard@gmail.com
 */
public class NodeManagerImpl extends JadeBaseComponent implements ClusterManager, ManagerService,	BindingController {

	/**
	 * The deployer used to deploy the nodes adlfile
	 */
	private org.objectweb.fractal.adl.Factory deployer;
	
	/**
	 * The registry
	 */
	private NamingService registry = null;
	
	/**
	 * The factory-client interface
	 */
	private NodeFactory factoryClient = null;
	
	/**
	 * The allocator interface
	 */
	private Allocator allocator = null;
	
	
	// --------------------------------------------------------------------------
	// Implementation of the BindingController interface
	// --------------------------------------------------------------------------
	protected String[] cItfs = new String[] {
      "deployer", "registry", "factory-client",
      "allocator"
  };
	
	public String[] listFc () {
		return super.concat(super.listFc(), cItfs);
	}

	public void bindFc (final String cItf, final Object sItf) throws NoSuchInterfaceException, IllegalBindingException, IllegalLifeCycleException {
		if (cItf.equals("deployer")) {
			deployer = (org.objectweb.fractal.adl.Factory)sItf;
		} else if (cItf.equals("registry")) {
			registry = (NamingService)sItf;
		} else if (cItf.equals("factory-client")) {
			factoryClient = (NodeFactory)sItf;
		} else if (cItf.equals("allocator")) {
			allocator = (Allocator)sItf;
		} else
		  super.bindFc(cItf, sItf);
	}
	
	
	public void unbindFc (final String cItf) throws NoSuchInterfaceException, IllegalBindingException, IllegalLifeCycleException {
		if (cItf.equals("deployer")) {
			deployer = null;
		} else if (cItf.equals("registry")) {
			registry = null;
		} else if (cItf.equals("factory-client")) {
			factoryClient = null;
		} else if (cItf.equals("allocator")) {
			allocator = null;
		} else
		  super.unbindFc(cItf);
	}
	
	public Object lookupFc (final String cItf) throws NoSuchInterfaceException {
		if (cItf.equals("deployer")) {
			return deployer;
		} else if (cItf.equals("registry")) {
			return registry;
		} else if (cItf.equals("factory-client")) {
			return factoryClient;
		} else if (cItf.equals("allocator")) {
			return allocator;
		}
		return super.lookupFc(cItf);
	}
	
	
	// --------------------------------------------------------------------------
	// Implementation of the ManagerService interface
	// --------------------------------------------------------------------------
	
	private String clusterId = null;
	
	public void deploy(String adlId) throws JadeException
	{
		Component rootCluster = null;
		
		if (adlId !=null) {
			
			try {
				
				log("Deploying "+adlId+" ...");
				Map<String, Object> context = new HashMap<String, Object>();
				//TODO remove this very bad thing 
				context.put("bootstrap", Boot.dirty);
				rootCluster = (Component)deployer.newComponent(adlId, context);
				
				log(adlId+" deployed ...\n");
				// register the root clusters in the clustermanager
				// TODO
				
				// register the root cmp of the cluster in the registry
				try {
					
					if(clusterId == null)
						clusterId = adlId;
					registry.rebind(adlId, rootCluster); 
					log(adlId+" registered ...\n");
				} catch (Exception e) {
					throw new JadeException("Cannot register nodes root in registry: " + e);
					
				}
			} catch (Exception e) {
				e.printStackTrace();
				throw new JadeException("Cannot start node manager: " + e);
			}
		}
		
	}
	
	

    public void start(String adlId) throws JadeException {       
        //Nothing to do in the case of the cluster manager
        //TODO provide a field representing the lifecycle state 
    }


    /* (non-Javadoc)
     * @see fr.jade.service.ManagerService#undeploy(java.lang.String)
     */
    public void stop(String adlId) throws JadeException {
        throw new JadeException("Not Yet Implemented");  
    }

	// --------------------------------------------------------------------------
	// Implementation of the ClusterManager interface
	// --------------------------------------------------------------------------

	public Component addNode(String physical, String virtual)
		throws InstantiationException
	{
		try{
			Component node = factoryClient.newNode(physical, virtual);
			return node;
		}catch(Exception e){
			throw new InstantiationException("Add node error");
		}
	}

}
